package com.example.demo.util;

import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Validator {

    private InputStream certificateFile;

    static InputStream getResourceFile(String file){
//        ClassLoader loader = Validator.class.getResource();
//        Validator.class.getResourceAsStream(file);
//        Validator.class.getResourceAsStream("/com.example.demo.util/"+file);
        return Validator.class.getResourceAsStream(file);
    }

    public static void main(String[] args){
        Validator validator = new Validator();
        validator.validate("F2ABILOmw1WgP5LyN8w64AG2cv1+BRPQ+odJ424Fioj3R5evXyCh7MUqILzU/bjLmXajE3gVfXB0nvovh7h1aQ1flQ+uhBpfVvpftvEYV/ztXUeoJPtKaKLT1FaYJfTsSDh5zFYicZmRmAJLtkyoU87zl0MR8jpSHKW3Sjt/cAdC5q0suAC49BkD/fMnY4fotGvn9epbcX9eagChb1cKSh23DJsl8RuTIoHeiVdMDWgcz/q4eYFuOVTLaQxXufxoKAOoyl4bdQA1ar/09//Qry4lpRCEoPJM+gQNJwcTsz417loqxTPmGQpSZZM0w+ujpyZt/52UZsaLtgX4iVIRY3erK1kfcqrpiFV8ZZm2VH+Hsi1bH+cm5JIiu8qG0sNdBfOdtBjfdx0514iW7VO1qWB6fT8sT+lbwk1HfXphjNXDO/e0hwYMoAl4X/dzxQHb0+bY/Gg6ZGSWZFsCi4J1M40saVvGpvymg5KL1mYcV+C3Z4slfd17YvBlDj2Gc/SoT51wM965rsVdWHi5IytyOn/vXRpV17uVWsDSXMw+gINt8YOhS2+eDWuKc+I1Upak6UqHfc+0Kl8aKEavXN/OT978Ccd/CYjzPd4dtEehIaBn7Q+B6zz7S1493L5ogGDDy62I5cQXABJxhCwxGGg7UfXic2zaUPr2c7cPLXSb0Tc=\n");
//        validator.validate("AKXTPdLiCHwjMuZpAIWZ38GvcY3euIu3JbU74vsQ+wVHG5aLiDRl7xLZChiqxEWs8RqPRcI4AK6JVtAC32+/hHpk+8zFqfkx+mWc4BkFkRkDa80CUz9BcGkEjVJR4XLyD8GVrHLysMnwqGCsIT0gAy9ngNd0sn8wzb6aBLItiho3+TR6pSNd/VayP4A+PHP9h/EJ23vMOlSzMPIzWCeLzy20qpVWGKwpAB9yyuZMwuzJRFPdT9X0faAUwWBoCZHVA+BPa9qmukloo1vggK8xuICNxXUqOMWy1AzNBcbBBsfa22qbbHFkvjSZSlxBeOodULbnHXdi9lrKtZ8+Uw/RcYtwQbFTW4XddCdypIB5wa9J6LON+gFt7udh0Vt5Dsyh8MWnNOk/PLTQ1SU5u4ktuwHgIwCny3wVWi37mG3RiRvHq+Emw2x9Uf5yZuGqsjsNoq10G42/gCa1aOWwPFJfychhq0mItqRvP5PrVVSPhRl+61SUfwP+tMyWw+hNREr/hzGbF1bZv1wDoLA9aNqDfdPHv958HBuHPwVWA3MEOw7nAqrPJYO+Bfm5dA5TzuBvyYtDCKmONXpZ1wFuDga6oTnMjRJHW6TfX/uF/t+nn2mSZ1X+emCg/PoHIFLu48U4sZgN0VPNjszzHTWtLPuAaQtJJTAY6kxVpw29LsODrS0=\n");
    }

    public JSONObject validate(String encryptedData){
        JSONObject result = new JSONObject();
        String decryptedData = decByPrivateKey(encryptedData);

        System.out.println("解密成功，数据如下：\n"+decryptedData);

        JSONObject message = null;
        try {
            message = JSONObject.fromObject(decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("errorCode","1009");
        }


        String sign = null;
        String content = null;
        String appId = null;
        try {
            sign = message.getString("sign");
            content = message.getString("content");
            appId = message.getString("appId");
        } catch (Exception e) {
            e.printStackTrace();
            result.put("errorCode","1002");
        }

        if(doVerifyPublicKey(appId,content,sign)){

            ParameterValidator p = new ParameterValidator();
            try {
                result = p.validate(content);
            } catch (Exception e) {
                e.printStackTrace();
            }

            System.out.println("APPID【kt-finance-rm】验签成功，数据安全有效。");
        }else{
            System.out.println("验签失败");
            result.put("errorCode","1002");
        }
        System.out.println("解密完成------------------>"+result);
        return result;
    }

    public Validator() {
        certificateFile = getResourceFile("certificate.crt");
    }

    private byte[] getKey(InputStream file) {
        byte[] keyBytes = null;
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            IOUtils.copy(file,bos);

//            DataInputStream dataInputStream = new DataInputStream(file);
//            keyBytes = new byte[(int) file.length()];
//            dataInputStream.readFully(keyBytes);
//            dataInputStream.close();
            bos.close();;
            keyBytes = bos.toByteArray();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Validator.class.getName()).log(Level.SEVERE, null,
                    ex);
        } catch (IOException ex) {
            Logger.getLogger(Validator.class.getName()).log(Level.SEVERE, null,
                    ex);
        }

        return keyBytes;
    }

    private  String decByPrivateKey(String data) {
        String dataBack = "";
        try {
            if (!StringUtils.isEmpty(data)) {
                byte[] Bytes = decryptWithPrivateKey(
                        Base64.decodeBase64(data), 0,
                        Base64.decodeBase64(data).length,
                        getKey(certificateFile));
                dataBack = new String(Bytes);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataBack;
    }

    private byte[] decryptWithPrivateKey(byte[] data, int offSet,
                                               int length, byte[] keyBytes) throws Exception {
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(2, privateK);
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        int i = 0;

        while (length - offSet > 0) {
            byte[] cache;
            if (length - offSet > 128) {
                cache = cipher.doFinal(data, offSet, 128);
            } else {
                cache = cipher.doFinal(data, offSet, length - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 128;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    public boolean doVerifyPublicKey(String appId, String data, String sign) {
        Boolean returnFlag = Boolean.FALSE;
        if ((StringUtils.isEmpty(data)) || (StringUtils.isEmpty(sign))) {
            return Boolean.FALSE.booleanValue();
        }
        try {
            returnFlag = Boolean.valueOf(verify(data.getBytes(), 0,
                    data.getBytes().length,
                    getKey(getResourceFile(appId+".key")),
                    Base64.decodeBase64(sign)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnFlag.booleanValue();
    }

    private boolean verify(byte[] data, int offset, int length, byte[] publicKeyBytes, byte[] dataSignature) {
        boolean result = false;
        try {
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
                    publicKeyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            Signature signature = Signature.getInstance("MD5withRSA");

            signature.initVerify(publicKey);

            signature.update(data, offset, length);

            result = signature.verify(dataSignature);
        } catch (Exception ex) {
            Logger.getLogger(Validator.class.getName()).log(Level.SEVERE, null,
                    ex);
        }

        return result;
    }

}
